module ActiveRecordExtras
  module Relation
    extend ActiveSupport::Concern

    module ClassMethods
      def update_or_create(attributes = {})
        assign_or_new(attributes).save
      end

      def update_or_create!(attributes = {})
        assign_or_new(attributes).save!
      end

      def assign_or_new(attributes)
        obj = first || new
        obj.assign_attributes(attributes)
        obj
      end
    end
  end
end

ActiveRecord::Base.send :include, ActiveRecordExtras::Relation

ActiveRecord::Associations::CollectionProxy.class_eval do
  # order a collection by custom fields
  # Arguments:
  # key: (String) Custom field key
  # order: (String) order direction (ASC | DESC)
  # sample: CamaleonCms::Site.first.posts.sort_by_field("untitled-field-attributes", "desc")
  def sort_by_field(key, order = "ASC")
    self.joins("LEFT OUTER JOIN #{Zerocms::CustomFieldsRelationship.table_name} ON #{Zerocms::CustomFieldsRelationship.table_name}.objectid = #{self.build.class.table_name}.id").where("#{Zerocms::CustomFieldsRelationship.table_name}.custom_field_slug = ? and #{Zerocms::CustomFieldsRelationship.table_name}.object_class = ?", key, self.build.class.name.parseCamaClass).reorder("#{Zerocms::CustomFieldsRelationship.table_name}.value #{order}")
  end

  # Filter by custom field values
  # Arguments:
  # key: (String) Custom field key
  # sample: my_posts_that_include_my_field = CamaleonCms::Site.first.posts.filter_by_field("untitled-field-attributes")
  #   this will return all posts of the first site that include custom field "untitled-field-attributes"
  #   additionally, you can add extra filter: my_posts_that_include_my_field.where("#{CamaleonCms::CustomFieldsRelationship.table_name}.value=?", "my_value_for_field")
  def filter_by_field(key, args = {})
    res = self.joins("LEFT OUTER JOIN #{Zerocms::CustomFieldsRelationship.table_name} ON #{Zerocms::CustomFieldsRelationship.table_name}.objectid = #{self.build.class.table_name}.id").where("#{Zerocms::CustomFieldsRelationship.table_name}.custom_field_slug = ? and #{Zerocms::CustomFieldsRelationship.table_name}.object_class = ?", key, self.build.class.name.parseCamaClass)
    res = res.where("#{Zerocms::CustomFieldsRelationship.table_name}.value = ?", args[:value]) if args[:value]
    res
  end
end


# add cache_var for models
ActiveRecord::Base.class_eval do
  # save cache value for this key
  def zerocms_set_cache(key, val)
    @zerocms_cache_vars ||= {}
    @zerocms_cache_vars[zerocms_build_cache_key(key)] = val
    val
  end

  # remove cache value for this key
  def zerocms_remove_cache(key)
    @zerocms_cache_vars.delete(zerocms_build_cache_key(key))
  end

  # fetch the cache value for this key
  def zerocms_fetch_cache(key)
    @zerocms_cache_vars ||= {}
    _key = zerocms_build_cache_key(key)
    if @zerocms_cache_vars.has_key?(_key)
      # puts "*********** using model cache var: #{_key}"
      @zerocms_cache_vars[_key]
    else
      @zerocms_cache_vars[_key] = yield
      @zerocms_cache_vars[_key]
    end
  end

  # return the cache value for this key
  def zerocms_get_cache(key)
    @zerocms_cache_vars ||= {}
    @zerocms_cache_vars[zerocms_build_cache_key(key)] rescue nil
  end

  # internal helper to generate cache key
  def zerocms_build_cache_key(key)
    _key = "zerocms_cache_#{self.class.name}_#{self.id}_#{key}"
  end
  
  # check if an attribute was changed
  def zerocms_attr_changed?(attr_name)
    if self.methods.include?(:saved_change_to_attribute?)
      self.saved_change_to_attribute?(attr_name.to_sym)
    else
      self.send("#{attr_name}_changed?")
    end
  end
end